package com.only4play.practice.pay.reconcile.core.strategy.download;

import cn.hutool.core.util.StrUtil;
import com.ijpay.core.enums.SignType;
import com.ijpay.core.kit.WxPayKit;
import com.ijpay.wxpay.WxPayApi;
import com.ijpay.wxpay.model.DownloadBillModel;
import lombok.extern.slf4j.Slf4j;
import org.dromara.x.file.storage.core.FileStorageService;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.io.*;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.FileChannel;
import java.nio.channels.ReadableByteChannel;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * @author mengdy
 */
@Slf4j
@Component
public class WeiXinBillFileDownStrategy{

    @Resource
    private FileStorageService fileStorageService;

    public File downloadFile(Map<String,String> params) throws Exception{

        int retryTimesParams = Integer.parseInt(params.get("retryTimes") == null ? "3" : params.get("retryTimes"));
        File file = null;
        int retryTimes = 0;
        while (file == null && retryTimes++ < retryTimesParams){
            try{
                // 是否沙箱环境
                String sandbox = params.get(WeChatParamNameConstant.IS_SANDBOX);

                // 是否服务商模式
                String isParentServe = params.get(WeChatParamNameConstant.IS_PARENT_SERVE);
                String appId = params.get(WeChatParamNameConstant.APPID);
                String mchId = params.get(WeChatParamNameConstant.MCH_ID);
                String subMchId = params.get(WeChatParamNameConstant.SUB_MCH_ID);
                String subAppId = params.get(WeChatParamNameConstant.SUB_MCH_ID);

                String billDate = params.get(WeChatParamNameConstant.BILL_DATE);
                String billType = params.get(WeChatParamNameConstant.BILL_TYPE);
                String tarType = params.get(WeChatParamNameConstant.BILL_TAR_TYPE);

                String partnerKey = params.get(WeChatParamNameConstant.PARTNER_KEY);

                DownloadBillModel.DownloadBillModelBuilder builder = DownloadBillModel.builder();
                // 是否服务商模式
                if (Objects.equals(isParentServe, WeChatParamNameConstant.VALUE_TRUE)) {
                    builder.appid(appId)
                            .mch_id(mchId)
                            .sub_appid(subAppId)
                            .sub_mch_id(subMchId);
                } else {
                    builder.appid(appId)
                            .mch_id(mchId);
                }

                DownloadBillModel downloadBillModel = builder
                        .bill_date(billDate)
                        .bill_type(billType)
                        .tar_type(tarType)
                        .nonce_str(WxPayKit.generateStr())
                        .build();

                Map<String, String> reqParams = downloadBillModel.createSign(partnerKey, SignType.HMACSHA256);

                String s = WxPayApi.downloadBill(Objects.equals(sandbox, WeChatParamNameConstant.VALUE_TRUE), reqParams);
//                System.out.println(responseStr);
//                if (responseStr != null){
////                    InputStream inputStream = new ByteArrayInputStream(responseStr.getBytes());
//                    // 上传文件
//                    byte[] bytes = responseStr.getBytes();
//                    UploadPretreatment uploadPretreatment = fileStorageService.of(bytes);
//                    String fileName = billDate+ "-" + billType + System.currentTimeMillis()+ "-" + ".txt";
//                    uploadPretreatment.setOriginalFilename(fileName);
//                    FileInfo upload = uploadPretreatment.upload();
////                    return upload.getUrl();
//                    // 生成文件
//                    try (FileOutputStream fos = new FileOutputStream(fileName)) {
//                        // 将字节数组写入文件
//                        fos.write(bytes);
//                        System.out.println("String has been written to file successfully.");
//                    } catch (IOException e) {
//                        throw new RuntimeException("写入账单文件失败");
//                    }
//                }
            }catch (Exception e){
                log.error("下载账单文件失败", e);
                throw new RuntimeException("下载账单文件失败");
            }
        }
        return null;
    }

    public InputStream getBillFileInputStream(Map<String,String> params){
        int retryTimesParams = Integer.parseInt(params.get("retryTimes") == null ? "3" : params.get("retryTimes"));
        InputStream inputStream = null;
        int retryTimes = 0;
        while (inputStream == null && retryTimes++ < retryTimesParams){
            try{
                // 是否沙箱环境
                String sandbox = params.get(WeChatParamNameConstant.IS_SANDBOX);

                // 是否服务商模式
                String isParentServe = params.get(WeChatParamNameConstant.IS_PARENT_SERVE);
                String appId = params.get(WeChatParamNameConstant.APPID);
                String mchId = params.get(WeChatParamNameConstant.MCH_ID);
                String subMchId = params.get(WeChatParamNameConstant.SUB_MCH_ID);
                String subAppId = params.get(WeChatParamNameConstant.SUB_MCH_ID);

                String billDate = params.get(WeChatParamNameConstant.BILL_DATE);
                String billType = params.get(WeChatParamNameConstant.BILL_TYPE);
                String tarType = params.get(WeChatParamNameConstant.BILL_TAR_TYPE);

                String partnerKey = params.get(WeChatParamNameConstant.PARTNER_KEY);

                DownloadBillModel.DownloadBillModelBuilder builder = DownloadBillModel.builder();
                // 是否服务商模式
                if (Objects.equals(isParentServe, WeChatParamNameConstant.VALUE_TRUE)) {
                    builder.appid(appId)
                            .mch_id(mchId)
                            .sub_appid(subAppId)
                            .sub_mch_id(subMchId);
                } else {
                    builder.appid(appId)
                            .mch_id(mchId);
                }
                DownloadBillModel downloadBillModel = builder
                        .bill_date(billDate)
                        .bill_type(billType)
//                        .tar_type(tarType)
                        .nonce_str(WxPayKit.generateStr())
                        .build();
                Map<String, String> reqParams = downloadBillModel.createSign(partnerKey, SignType.HMACSHA256);
                String responseStr = WxPayApi.downloadBill(Objects.equals(sandbox, WeChatParamNameConstant.VALUE_TRUE), reqParams);
                if (StrUtil.isNotEmpty(responseStr) && !responseStr.contains("<xml>")){
                    inputStream = new ByteArrayInputStream(responseStr.getBytes());
                }else if (responseStr.contains("No Bill Exist")){
                    responseStr = WeChatParamNameConstant.WECHAT_V2_BILL_FILE_HAS_NO_BILL_EXIST_DEFAULT_CONTENT;
                    inputStream = new ByteArrayInputStream(responseStr.getBytes());
                }else {
                    log.error("下载账单文件失败 = {}", responseStr);
                    responseStr = responseStr.replace("\n", "");
                    inputStream = new ByteArrayInputStream(responseStr.getBytes());
                }
            }catch (Exception e){
                log.error("下载账单文件失败", e);
                throw new RuntimeException("下载账单文件失败");
            }
        }
        return inputStream;
    }
    public static void main(String[] args) throws Exception {

        HashMap<String, String> hashMap = new HashMap<>();
        hashMap.put("sandbox","0");
        hashMap.put("appId","wx21f3457973e9fc5d");
        hashMap.put("mchId","1589812661");
        hashMap.put("partnerKey","1bc8ed288f606b7938f8d6e428101a98");
        hashMap.put("interfaceVersion","v2");
        hashMap.put("billType","ALL");
        hashMap.put("billDate","20240919");
        hashMap.put("isParentServe","0");
//        File downloadFile = downloadFile(hashMap);

//        System.out.println("hello world  " + downloadFile);

    }

    public static File saveFile(InputStream is, File file) throws IOException {

        // 判断父文件是否存在,不存在就创建
        if (!file.getParentFile().exists()) {
            if (!file.getParentFile().mkdirs()) {
                // 新建文件目录失败，抛异常
                throw new IOException("创建文件(父层文件夹)失败, filepath: " + file.getAbsolutePath());
            }
        }
        // 判断文件是否存在，不存在则创建
        if (!file.exists()) {
            if (!file.createNewFile()) {
                // 新建文件失败，抛异常
                throw new IOException("创建文件失败, filepath: " + file.getAbsolutePath());
            }
        }

        FileOutputStream fileOut = null;
        FileChannel fileChannel = null;
        try {
            fileOut = new FileOutputStream(file);
            fileChannel = fileOut.getChannel();

            ReadableByteChannel readableChannel = Channels.newChannel(is);
            ByteBuffer buffer = ByteBuffer.allocate(1024 * 32);
            while (true) {
                buffer.clear();
                if (readableChannel.read(buffer) == -1) {
                    readableChannel.close();
                    break;
                }
                buffer.flip();
                fileChannel.write(buffer);
            }
            return file;
        } catch (FileNotFoundException e) {
            throw new FileNotFoundException("保存账单文件失败, filepath: " + file.getAbsolutePath());
        } catch (IOException e) {
            throw new IOException("保存账单文件失败, filepath: " + file.getAbsolutePath(), e);
        } finally {
            if (fileOut != null) {
                try {
                    fileOut.close();
                } catch (IOException e) {
                    log.error("保存账单时关闭流失败", e);
                }
            }
            if (is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                    log.error("保存账单时关闭流失败", e);
                }
            }
            if (fileChannel != null) {
                try {
                    fileChannel.close();
                } catch (IOException e) {
                    log.error("保存账单时关闭流失败", e);
                }
            }
        }
    }
}
